/*
** File: hey_signal.c
** Desc: Sets up signals for C version of hey
** Auth: Cian Synnott <pooka@redbrick.dcu.ie>
** Date: Mon Nov 16 01:27:24 GMT 1998
**
** $Id: hey_signal.c,v 1.4 2003-08-11 01:21:45 c-hey Exp $
*/

#include <termios.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "hey_signal.h"
#include "hey_readline.h"
#include "hey_edit.h"
#include "aux.h"

#include "config.h"

/* Print out some haikus on certain signals - why not? ;o)
** the TERM & INT ones are mine; the SEGV one comes from a haiku_errors.txt
** of some sort; I believe it's under http://www.gnu.org/fun/ somewhere? */
RETSIGTYPE hey_signal_handler(int sig) {
	switch (sig) {
		case SIGTERM: 
			printerr_exit("                         \"to all men comes death\n"
		                      "                          a termination signal -\n"
				      "                          this process must die\"\n");

		case SIGSEGV:
			printerr_exit("\n                         \"wind catches lily\n"
				          "                          scatt'ring petals o'er water -\n"
					  "                          segmentation fault\"\n\n"
					  "           If you could, I'd appreciate you copying down the input\n"
					  "              that produced this fault and mailing it to me at\n"
					  "                          pooka@redbrick.dcu.ie\n"
					  "        Thanks, if you try a slight variation on that input is should work.\n\n");

		case SIGINT:
			printerr_exit("\n                         \"continuation\n"
					  "                          is for this process a dream -\n"		
					  "                          interruption caught\"\n\n");
		case SIGCONT:	
			hey_redisplay();
			break;
		default:
			printerr_exit("Dodgy unwaited-for signal caught. Bailing out.\n");
	}
	
	return;

}

/* Just setup all the signal handlers - ignore silly ones ... */
void hey_signal_setup(void) {
	sigset_t set;

	/* Start with a full set */
	sigfillset(&set);

	/* Delete the ones we're interested in from it */
	sigdelset(&set, SIGINT);
	sigdelset(&set, SIGSEGV);
	sigdelset(&set, SIGTERM);
	sigdelset(&set, SIGTSTP);
	sigdelset(&set, SIGCONT);
	
	/* Block all the signals remaining in the set */
	sigprocmask(SIG_BLOCK, &set, NULL);

	/* Catch the others */
	signal(SIGINT, hey_signal_handler);
	signal(SIGSEGV, hey_signal_handler);
	signal(SIGTERM, hey_signal_handler);
	signal(SIGCONT, hey_signal_handler);	
	
	return;
}

/* 
** Functions & global for fiddling about with terminal settings 
** Put them here because I'm really doing it as a signals problem, 
** namely that ^S from the keyboard (easy to type instead of EOF, ^D)
** would suspend the process & wait for ^Q, which many people are 
** unaware of. 
*/

struct termios saved_term;

/* The atexit() cleanup to put the terminal back in it's normal state. */
void hey_terminal_cleanup(void) {
	tcsetattr(STDIN_FILENO, TCSANOW, &saved_term);
	return;
}

/* The terminal setup routine - removes the possibility of using CTRL-S as
** SIGSTOP */
void hey_terminal_setup(void) {
	struct termios change;

	tcgetattr(STDIN_FILENO, &saved_term);

	memcpy(&change, &saved_term, sizeof(struct termios));

	/* Change the ^Q & ^S keys to do nothing special... */
	change.c_cc[VSTART] = 0;
	change.c_cc[VSTOP]  = 0;

	tcsetattr(STDIN_FILENO, TCSANOW, &change);

	/* Register the cleanup routine that puts the terminal back 
	** in it's initial state ... */
	if (atexit(hey_terminal_cleanup)) 
		printerr_exit("hey: failed to register terminal atexit()\n");

	return;
}
